package top.caulife.lab.entity.bookingTime;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


class StageIndex implements Comparable<StageIndex> {
    public Date time;
    public int num;
    public StageIndex(Date t, int n) {
        time = t;
        num = n;
    }

    @Override
    public int compareTo(StageIndex o) {
        return this.time.compareTo(o.time);
    }
}

public class TimeSlot {     // 多个时间段
    public List<Stage> tS;  // 多个时间段

    public TimeSlot() { tS = new ArrayList<>(); }
    public TimeSlot(Stage st) {
        tS = new ArrayList<>();
        tS.add(st);
    }

    enum OpType { INTER, UNION }

    static boolean mix(boolean a, boolean b, OpType op) {
        if (op==OpType.INTER) return a && b;
        else if (op==OpType.UNION) return a || b;
        else return false;
    }

    static TimeSlot opTime(TimeSlot one, TimeSlot two, OpType op) {  // 交集
        TimeSlot timeSlot = new TimeSlot();
        List<StageIndex> sis = new ArrayList<>();
        for (Stage oi : one.tS) {
            sis.add(new StageIndex(oi.startTime, 1));
            sis.add(new StageIndex(oi.endTime, 1));
        }
        for (Stage ti : two.tS) {
            sis.add(new StageIndex(ti.startTime, 2));
            sis.add(new StageIndex(ti.endTime, 2));
        }
        Collections.sort(sis);

        boolean oneing = false, twoing = false,
                ing = false;
        List<Date> out = new ArrayList<>();
        for (StageIndex si : sis) {
            if (si.num == 1) oneing = !oneing;
            if (si.num == 2) twoing = !twoing;
            if (ing != mix(oneing, twoing, op)) {
                out.add(si.time);
                ing = !ing;
            }
        }
        assert !(oneing||twoing||ing);
        for (int i=0; i<out.size(); i+=2) {
            timeSlot.tS.add(new Stage(out.get(i), out.get(i+1)));
        }
        return timeSlot;
    }

    public static TimeSlot inter(TimeSlot one, TimeSlot two) {  // 时间段交集
        return opTime(one, two, OpType.INTER);
    }

    public static TimeSlot union(TimeSlot one, TimeSlot two) {  // 时间段并集
        return opTime(one, two, OpType.UNION);
    }

    public TimeSlot addInter(Stage st) {    // 单个时间段交集加入
        return inter(this, new TimeSlot(st));
    }

    public TimeSlot addUnion(Stage st) {    // 单个时间段并集加入
        return union(this, new TimeSlot(st));
    }

    public TimeSlot addInter(TimeSlot other) {    // 单个时间段交集加入
        return inter(this, other);
    }

    public TimeSlot addUnion(TimeSlot other) {    // 单个时间段并集加入
        return union(this, other);
    }

    public static class Stage {       // 单个时间段
        public Date startTime;
        public Date endTime;
        public Stage(Date s, Date e) {
            startTime = s;
            endTime = e;
        }
    }
}
